package io.kimmking.chatoom.client.boot;

import io.kimmking.chatoom.client.handler.NettyClientMsgHandler;
import io.kimmking.dubbo.common.service.charroom.CharRoomSelectorService;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;

@Slf4j
public class NettyClientBootStrap {

    private final NettyClientMsgHandler nettyClientMsgHandler;

    private final static EventLoopGroup work = new NioEventLoopGroup();

    private Channel channel;

    /**
     * 构造方法
     * @param nettyClientMsgHandler
     */
    public NettyClientBootStrap (final NettyClientMsgHandler nettyClientMsgHandler) {

        this.nettyClientMsgHandler = nettyClientMsgHandler;

    }

    /**
     * 连接NettyServer，发起聊天操作
     * @param charRoomSelectorService
     * @throws Exception
     */
    public void startBootStrap(final CharRoomSelectorService charRoomSelectorService) throws Exception {
        String ip = null;
        int port = 8088;
        try {
            //先从Redis或者ZK中选择一个NettyServer进行连接
            String selectedNettyServer = charRoomSelectorService.selectorFromList();
            if (Objects.isNull(selectedNettyServer))
                throw new RuntimeException("no alive netty server from ZK found!");

            if (!selectedNettyServer.contains("_"))
                throw new RuntimeException("netty server information wrong format!");
            ip = selectedNettyServer.split("_")[0];
            port = Integer.parseInt(selectedNettyServer.split("_")[1]);
        } catch (Exception e) {
            log.error("new NettyClientBootStrap failed with Exception: {}", e.toString());
        }

        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(work);
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.handler(new ChannelInitializer<NioSocketChannel>() {
            @Override
            protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                ChannelPipeline pipeline = nioSocketChannel.pipeline();
                pipeline.addLast("encoder", new StringEncoder());
                pipeline.addLast("decoder", new StringDecoder());
                pipeline.addLast(nettyClientMsgHandler);
            }
        });

        ChannelFuture channelFuture = bootstrap.connect(ip, port).sync();
        channel = channelFuture.channel();
        channelFuture.addListener(future -> {
            if(future.isSuccess())
                log.info("Netty客户端启动中。。。。。。。");
            if(future.isDone())
                log.info("Netty客户端启动成功,客户端地址: {}", channel.localAddress().toString());
        });

        //监听channel关闭事件
        channel.closeFuture().sync();
        channelFuture.addListener(future -> {
            if(future.isCancelled())
                log.info("Netty客户端正在关闭中。。。。。。。");
            if(future.isCancellable())
                log.info("Netty客户端已经关闭。。。。。。。");
        });
    }

    /**
     * 向Netty服务端发送消息
     * @param msg
     */
    public void sendMessage (String msg) {
        if (Objects.isNull(channel))
            throw new RuntimeException("channel is null, can not send msg");
        channel.writeAndFlush(msg + "\n");
    }

    protected void close() throws Exception {
        Objects.requireNonNull(channel, "channel is null!").close();
        work.shutdownGracefully();
    }

}
